using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DslCrossModelFramework.ModelRelationship;
using DslCrossModelFramework.ModelTraversal;
using Microsoft.VisualStudio.Modeling;

namespace DslCrossModelFramework.UI {
    public partial class ModelElementTreeDialog : Form {
        public ModelElementTreeDialog(CrossModelManager manager, RelationshipDefinitionDelegate relationshipDelegate, string scope, ModelSelectionMode mode, ModelPath currentValue) : this(manager, relationshipDelegate, scope, mode, currentValue, null) {
        }

        public ModelElementTreeDialog(CrossModelManager manager, RelationshipDefinitionDelegate relationshipDelegate, string scope, ModelSelectionMode mode, ModelPath currentValue, ModelElement rootElement) {
            this.manager = manager;
            this.relationshipDefinitionDelegate = relationshipDelegate;
            this.scope = scope;
            this.selectionMode = mode;
            this.startingPath = currentValue;
            this.rootModelElement = rootElement;
            InitializeComponent();
            OKButton.Enabled = false;
        }

        private string scope = string.Empty;
        public string Scope {
            get { return scope; }
            set{ scope = value;}
        }

        private CrossModelManager manager;
        /// <summary>
        /// Gets the manager.
        /// </summary>
        /// <value>The manager.</value>
        public CrossModelManager Manager {
            get { return manager; }
        }

        /// <summary>
        /// Gets or sets the dialog title.
        /// </summary>
        /// <value>The dialog title.</value>
        public string DialogTitle {
            get { return this.Text; }
            set { this.Text = value; }
        }

        private RelationshipDefinitionDelegate relationshipDefinitionDelegate;
        /// <summary>
        /// Gets or sets the relationship definition delegate. 
        /// When set, the delegate will be used to obtain relationships from parent to child
        /// </summary>
        /// <value>The relationship definition delegate.</value>
        public RelationshipDefinitionDelegate RelationshipDefinitionDelegate {
            get { return relationshipDefinitionDelegate; }
            set { relationshipDefinitionDelegate = value; }
        }

        private ModelPath startingPath;
        /// <summary>
        /// Gets or sets the starting path.
        /// </summary>
        /// <value>The starting path.</value>
        public ModelPath StartingPath {
            get { return startingPath; }
            set{ startingPath = value;}
        }

        private ModelSelectionMode selectionMode;
        /// <summary>
        /// Gets or sets the selection mode.
        /// </summary>
        /// <value>The selection mode.</value>
        public ModelSelectionMode SelectionMode {
            get { return selectionMode; }
            set { selectionMode = value;  }
        }

        private ModelElement rootModelElement;

        /// <summary>
        /// Gets or sets the root model element. 
        /// When set the root element will be at the top rather than the solution and projects etc.
        /// </summary>
        /// <value>The root model element.</value>
        public ModelElement RootModelElement {
            get { return rootModelElement; } 
            set{ rootModelElement = value;}
        }


        /// <summary>
        /// Gets or sets a value indicating whether to allow the user to select none].
        /// </summary>
        /// <value><c>true</c> if [all select none]; otherwise, <c>false</c>.</value>
        public bool AllowSelectNone {
            get { return allowSelectNone; }
            set { allowSelectNone = value; }
        }

        private List<Guid> excludedStores = new List<Guid>();
        /// <summary>
        /// Gets or sets the store ids to exclude. 
        /// This can be used to exclude the current store for a cross model reference
        /// </summary>
        /// <value>The excluded store ids.</value>
        public List<Guid> ExcludedStores {
            get { return excludedStores; }
            set { excludedStores = value; }
        }


        private bool hideRoot;
        /// <summary>
        /// Gets or sets a value indicating whether [hide root].
        /// </summary>
        /// <value>If set to true then the root element will be hidden and its children will appear at the top of the tree.</value>
        public bool HideRoot {
            get { return hideRoot; }
            set{ hideRoot = value;}
        }

        public ModelElementFilterCollection SelectionFilters {
            get { return selectionFilters; }
            set{ selectionFilters = value;}
        }
        private ModelElementFilterCollection selectionFilters = new ModelElementFilterCollection();

        private ModelElementTree treeControl;


        public void Bind() {
            panel1.Controls.Clear();
            treeControl = new ModelElementTree(manager, relationshipDefinitionDelegate, scope, selectionMode, startingPath, rootModelElement);
            treeControl.AllowSelectNone = this.allowSelectNone;
            treeControl.ExcludedStores = this.excludedStores;
            treeControl.Bind();
            treeControl.SelectionChanged += new EventHandler<ModelItemSelectionEventArgs>(treeControl_SelectionChanged);
            treeControl.SelectNoneClicked += new EventHandler<EventArgs>(treeControl_SelectNoneClicked);
            treeControl.Dock = DockStyle.Fill;
            panel1.Controls.Add(treeControl);
            treeControl.Focus();
        }

        /// <summary>
        /// Handles the SelectNoneClicked event of the treeControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void treeControl_SelectNoneClicked(object sender, EventArgs e) {
            selectedPath = null;
            DialogResult = System.Windows.Forms.DialogResult.OK;
            Close();
        }

        /// <summary>
        /// Handles the SelectionChanged event of the treeControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DslCrossModelFramework.UI.ModelItemSelectionEventArgs"/> instance containing the event data.</param>
        protected virtual void treeControl_SelectionChanged(object sender, ModelItemSelectionEventArgs e) {
            if (e.SelectedModelPath != null && (selectionFilters.Count == 0 || selectionFilters.IsValid(e.SelectedModelPath.Last))) {
                OKButton.Enabled = e.IsModelElementSelected;
                selectedPath = e.SelectedModelPath;
            }
            else {
                OKButton.Enabled = false;
            }
        }

        /// <summary>
        /// Handles the Click event of the OKButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void OKButton_Click(object sender, EventArgs e) {
            DialogResult = System.Windows.Forms.DialogResult.OK;
            
            Close();
        }

        private string modelElementReference = string.Empty;
        public string ModelElementReference {
            get { return selectedPath == null ? null : selectedPath.SerializeToString();  }
        }

        public ModelPath SelectedPath {
            get { return selectedPath; }
        }
        private ModelPath selectedPath;
        private bool allowSelectNone = true;

        public ModelElement SelectedModelElement {
            get { return selectedPath == null ? null : selectedPath.TargetModelElement; }
        }

        private void modelElementListBox_SelectedIndexChanged(object sender, EventArgs e) {
            //OKButton.Enabled = modelElementListBox.SelectedIndex > -1;
        }

        private void CancelButton_Click(object sender, EventArgs e) {
            DialogResult = System.Windows.Forms.DialogResult.Cancel;
            Close();
        }
    }
}